package com.ilock.service;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gson.Gson;
import com.ilock.bean.Ilockinfo;
import com.ilock.bean.IlockinfoDAO;
import com.ilock.bean.Templockinfo;
import com.ilock.bean.TemplockinfoDAO;
import com.ilock.bean.Own;
import com.ilock.bean.OwnDAO;
import com.ilock.bean.Templockop;
import com.ilock.bean.TemplockopDAO;
import com.ilock.util.ICodeGenerator;
import com.ilock.bean.TemplockinfoDAO;

public class LockServiceImpl implements ILockService{
	
	private IlockinfoDAO IlockinfoDAO;
	private OwnDAO OwnDAO;
	private ICodeGenerator ICodeGenerator;
	private TemplockinfoDAO TemplockinfoDAO;
	private TemplockopDAO TemplockopDAO;
	
	public void setIlockinfoDAO(IlockinfoDAO IlockinfoDAO){
		this.IlockinfoDAO = IlockinfoDAO;
	}
	
	public void setICodeGenerator(ICodeGenerator ICodeGenerator){
		this.ICodeGenerator = ICodeGenerator;
	}
	
	public void setOwnDAO(OwnDAO ownDAO) {
		this.OwnDAO = ownDAO;
	}
	
	public TemplockopDAO getTemplockopDAO() {
		return TemplockopDAO;
	}

	public void setTemplockopDAO(TemplockopDAO templockopDAO) {
		TemplockopDAO = templockopDAO;
	}

	public IlockinfoDAO getIlockinfoDAO() {
		return IlockinfoDAO;
	}

	public OwnDAO getOwnDAO() {
		return OwnDAO;
	}

	public ICodeGenerator getICodeGenerator() {
		return ICodeGenerator;
	}

	public TemplockinfoDAO getTemplockinfoDAO() {
		return TemplockinfoDAO;
	}

	public void setTemplockinfoDAO(TemplockinfoDAO templockinfoDAO) {
		TemplockinfoDAO = templockinfoDAO;
	}

	/**
	 * check lock info
	 * @param locknumber
	 * @param password
	 * @return
	 */
	public Ilockinfo checkLockInfo(int locknumber,String password){
		return IlockinfoDAO.checkLockInfo(locknumber, password);
	}

	/**
	 * find lockinfo by token
	 * @param token
	 * @return
	 */
	public Ilockinfo findLockInfoByToken(String token){
			Ilockinfo tempilockinfo = null;
		try{
			List list = IlockinfoDAO.findByIlockInfoPassword(token);
			if(!list.isEmpty()){
				tempilockinfo = (Ilockinfo) list.get(0);
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		return tempilockinfo;
	}
	/**
	 * find lock by unique 
	 * @param password
	 * @return
	 */
	public Ilockinfo checkPassword(String password){
		Ilockinfo ilockinfo = null;
		List ilockinfoList = IlockinfoDAO.findByIlockInfoPassword(password);
		if(!ilockinfoList.isEmpty()){
			ilockinfo=(Ilockinfo) ilockinfoList.get(0);
		}
		return ilockinfo;
	}
	/**
	 * update lock's info
	 * @param ilockinfo
	 * @return
	 */
	public Ilockinfo updateLockInfo(Ilockinfo ilockinfo){
		IlockinfoDAO.update(ilockinfo);
		return IlockinfoDAO.findById(ilockinfo.getIlockInfoNumber());
	}
	
	/**
	 * bind user with his lockID and password
	 * @param lockID
	 * @param password
	 * @return
	 */
	public Map<String,Object> bindLock(int userID,int lockID,String password){
		Map<String,Object> map = new HashMap<String, Object>();
		Ilockinfo ilockinfo = IlockinfoDAO.findById(lockID);
		if(ilockinfo!=null){
			if(OwnDAO.checkBind(userID, ilockinfo.getIlockInfoNumber())!=null){
				map.put("state", "the user and lock has already been binded");
				this.deleteTempLockInfo(userID);
				System.out.println("userID:"+userID+" lockID:"+ilockinfo.getIlockInfoNumber()+" has already been binded");
			}else{
				Own own = new Own();
				own.setIuserNumber(userID);
				own.setLevel(0);
				own.setIlockInfoNumber(ilockinfo.getIlockInfoNumber());
				OwnDAO.merge(own);
				ilockinfo.setIlockInfoPassword(password);
				ilockinfo = this.updateLockInfo(ilockinfo);
				this.deleteTempLockInfo(userID);
				map.put("ilockinfo", ilockinfo);
				map.put("state", "bindDone");	
			}
		}else{
			map.put("state", "bindlock with wrong lockinfo");
		}
		return map;
	}
	
	/**
	 * generate new token
	 * @param lockID
	 * @param password
	 * @return
	 */
	public Ilockinfo getNewToken(String password){
		Ilockinfo ilockinfo =this.checkPassword(password);
		System.out.println("old token:"+password);
		if(ilockinfo!=null){
			try {
				ilockinfo.setIlockInfoPassword(this.ICodeGenerator.MD5Encoding(ilockinfo.getIlockInfoPassword()));
				String temppassword = ilockinfo.getIlockInfoPassword();
				if(temppassword.indexOf(" ")!=-1){
					temppassword = temppassword.replace(" ", "+");	
				}
				ilockinfo.setIlockInfoPassword(temppassword);
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return ilockinfo;
	}
	
	/**
	 * show user's lock list
	 * @param userID
	 * @return
	 */
	public List getUserLockList(int userID){
		List<Own> owns = OwnDAO.findByIuserNumber(userID);
		List<Ilockinfo> ilockinfo = new ArrayList<Ilockinfo>();
		for(int i=0;i<owns.size();i++){
			Integer templockNumber = owns.get(i).getIlockInfoNumber();
			if(templockNumber!=null){
			Ilockinfo tempilockinfo =IlockinfoDAO.findById(templockNumber);
			ilockinfo.add(tempilockinfo);
			}else{
				System.out.println("get userlock list lock number error");
			}
		}
		return ilockinfo;
	}
	
	/**
	 * get user's lockID  list
	 * @param userID
	 * @return
	 */
	public List getUserLockIDList(int userID){
		return OwnDAO.findByIuserNumber(userID);
	}
	
	/**
	 * delete user's whole locks
	 * @param userID
	 */
	public void deleteOwnLock(int userID){
		OwnDAO.deleteByUserID(userID);
	}
	
	/**
	 * insert temp match info to database
	 * @param userID
	 * @param lockID
	 * @param temppassword
	 * @return
	 */
	public Templockinfo insertTempLockInfo(int userID,int lockID,String temppassword){
		this.deleteTempLockInfo(userID);
		Templockinfo templockinfo = new Templockinfo();
		templockinfo.setIuserNumber(userID);
		templockinfo.setIlockInfoNumber(lockID);
		templockinfo.setTempPassword(temppassword);
		TemplockinfoDAO.save(templockinfo);
		templockinfo = null;
		List templockinfos =TemplockinfoDAO.findByIuserNumber(userID);
		if(!templockinfos.isEmpty()){
			templockinfo=(Templockinfo) templockinfos.get(0);
		}
		return templockinfo;
	}
	
	/**
	 * find temp info by userID
	 * @param userID
	 * @return
	 */
	public Templockinfo findTemplockInfo(int userID){
		Templockinfo templockinfo = null;
		List templockinfos =TemplockinfoDAO.findByIuserNumber(userID);
		if(!templockinfos.isEmpty()){
			templockinfo=(Templockinfo) templockinfos.get(0);
		}
		return templockinfo;
	}
	
	/**
	 * delete temp info by userID
	 * @param userID
	 */
	public void deleteTempLockInfo(int userID){
		List templockinfo = TemplockinfoDAO.findByIuserNumber(userID);
		if(!templockinfo.isEmpty()){
			for(int i=0;i<templockinfo.size();i++){
			TemplockinfoDAO.delete((Templockinfo)templockinfo.get(i));
			}
		}		
	}
	
	/**
	 * add lock/unlock info into database
	 * @param userID
	 * @param lockID
	 * @param operate
	 */
	public Templockop addTempLockOp(int userID,int lockID,int operate){
//		this.deleteTempLockOp(lockID);
		Templockop templockop = new Templockop();
		templockop.setIlockInfoNumber(lockID);
		templockop.setIuserNumber(userID);
		templockop.setOperate(operate);
		templockop.setIsdel(0);
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		templockop.setTime(Timestamp.valueOf(df.format(new Date())));
		TemplockopDAO.save(templockop);
		List templist  =  TemplockopDAO.findByIlockInfoNumber(lockID);
		templockop = null;
		if(!templist.isEmpty()){
			templockop = (Templockop) templist.get(0);
		}
		return templockop;
	}
	
	/**
	 *logical delete lock operation by lockID
	 * @param lockID
	 */
	public void deleteTempLockOp(int lockID){
		List<Templockop> templockopList = TemplockopDAO.findByIlockInfoNumber(lockID);
		if(!templockopList.isEmpty()){
			for(int i=0;i<templockopList.size();i++){
				Templockop templockop = templockopList.get(i);
				templockop.setIsdel(1);
				TemplockopDAO.merge(templockop);
			}
		}
	}
	/**
	 * find lock operation by lockID
	 * @param lockID
	 * @return
	 */
	public Templockop findTempLockOp(int lockID){
		List<Templockop> templockopList = TemplockopDAO.findByActive(lockID);
		Templockop templockop = null;
		if(!templockopList.isEmpty()){
			templockop = templockopList.get(0);
		}
		return templockop;
	}
	
	/**
	 * update lock's state
	 * @param lockID
	 * @return
	 */
	public Templockop updateTempLockOp(int lockID){
		List<Templockop> templockopList = TemplockopDAO.findByIlockInfoNumber(lockID);
		Templockop templockop = null;
		if(!templockopList.isEmpty()){
			templockop = templockopList.get(0);
			int tempOperate = templockop.getOperate();
			if(tempOperate==1){
				templockop.setOperate(0);
			}else{
				templockop.setOperate(1);
			}
			TemplockopDAO.merge(templockop);
		}
		return templockop;
	}
	
	public void updateTempLockOp(Templockop templockop){
		TemplockopDAO.merge(templockop);
	}
	
	public void addShare(int userID,int lockID){
		Own own = new Own();
		own.setIlockInfoNumber(lockID);
		own.setIuserNumber(userID);
		own.setLevel(1);
		OwnDAO.save(own);
	}
	
	public boolean checkOwner(int userID,int lockID){
		List tempList = OwnDAO.getOwnListByUserIDAndLockID(userID, lockID,0);
		if(!tempList.isEmpty()){
			return true;
		}else{
			return false;
	
		}
	}
	
	public boolean checkShareExist(int userID,int lockID){
		List tempList = OwnDAO.getOwnListByUserIDAndLockID(userID, lockID,1);
		if(!tempList.isEmpty()){
			return true;
		}else{
			return false;
	
		}
	}
	
	public Ilockinfo checkUserIDExist(int userID){
		return IlockinfoDAO.findById(userID);
	}
}
